# -*- coding: utf-8 -*-

# Copyright 2009 David Lee Miller
#
# This file is part of POSSM (Python Open Source Scanning Microscopy).
#
# POSSM is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# POSSM is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License         
# along with POSSM.  If not, see <http://www.gnu.org/licenses/>.
#                                                                           
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

import time,socket
from copy import copy
import worldsettings as ws
import scanvariables as sv
from shared import n

treelist = []
classlist = []

class MakeTree(object):
	'''
	This class takes all of the data arranged for an individual scan and makes it into
	a single package for display on the stm client controller. Each individual data value
	is referred to as a twig. Several twigs are arranged based on their similarity and given
	a group name such as 'Image Size'. Each group of twigs is a branch. Groups of branches
	are put together to contain all of the information needed for the controller to perform
	a scan. Following the convention, these groups of branches are called trees.
	
	'''
	def __init__(self, treename, branchnames, names, values, units, descr, cell,limits={}):	
		
		self.treename = treename
		self.branches = branchnames
		self.twigs = {}
		self.data = {}
		self.limits = limits
		
		for i,bname in enumerate(self.branches):
			self.data[bname] = self.SetData(names[i],values[i],units[i],descr[i],cell[i])
			self.twigs[bname] = names[i]
	
	def SetData(self,names,values,units,descr,cell):
		'''
		Pulls together all of the names, values and units for all of the twigs in
		a branch and returns that data as a dictionary.
		
		Keyword Arguments:
		names -- the name assiciated with each twig
		values -- the particular value for that twig
		units -- the units used to describe the value
		descr -- a description of the twigs role in a scan
		'''
		branchdata = {}
		for i,name in enumerate(names):
			branchdata[name] = [values[i],units[i],descr[i],cell[i]]
		return branchdata

class UnitOrganizer(object):
	'''
	Portable unit conversion class. All conversion units given
	in reference to standard units.
	'''
	bits = 16
	rng = 20.0
	VOLTSPERADU = rng/(2**bits)
	UNIT_NM = 1e-9
	UNIT_ANG = 1e-10
	UNIT_UM = 1e-6
	UNIT_MV = 1e-3
	UNIT_PA = 1e-12
	UNIT_NA = 1e-9
	UNIT_UA = 1e-6
	XVOLTS = ws.ANG_PER_VOLT_X*1e-10 # (volts corresponds to a dist)
	YVOLTS = ws.ANG_PER_VOLT_Y*1e-10
	ZVOLTS = ws.ANG_PER_VOLT_Z*1e-10
	AMPS = ws.NAMP_PER_VOLT*1e-9
	BIAS = 1 # (1 volt per volt)
	IVOLTS = 1
	SCAN_GAIN = ws.SCAN_GAIN
	units = {}
	def __init__(self):
		self.units['Volts'] = (self.ZVOLTS,'V')
		self.units['Millivolts'] = (self.UNIT_MV, 'mV')
		self.units['Picoamps'] = (self.UNIT_PA, 'pA')
		self.units['Microamps'] = (self.UNIT_UA, 'uA')
		self.units['Nanoamps'] = (self.UNIT_NA, 'nA')
		self.units['Nanometers'] = (self.UNIT_NM,'nm')
		self.units['Angstroms'] = (self.UNIT_ANG,'A')
		self.units['Microns'] = (self.UNIT_UM,'um')
	
	def _ConvertZScale(self,data,current_unit,desired_unit,zgain,zout):
		realzout = zout*10+1
		if current_unit == self.ZVOLTS and desired_unit == self.ZVOLTS: return data
		else: return n.multiply(data,((zgain*current_unit)/(desired_unit*realzout)))

	def _Convert(self,data,current_unit,desired_unit,gain):
		return n.multiply(data,(gain*current_unit/(desired_unit)))
	
	def _ConvertPixels(self,xlen,ylen,step,desired_unit,xgain,ygain):
		return xgain*self.SCAN_GAIN*xlen*step*self.VOLTSPERADU*self.XVOLTS/desired_unit,ygain*self.SCAN_GAIN*ylen*step*self.VOLTSPERADU*self.YVOLTS/desired_unit

class ScanExecutor(object):
	'''
	Used for organizing scans into generic executable code. 
	'''
	code = []
	def __init__(self,scan,package):
		self.scan=scan
		self.package=package
		#self.name=self.package.TYPE
	
	def _exec_code(self,**kwds):
		for i in kwds.keys(): exec i+'=kwds[i]'
		if type(self.code)==list or type(self.code)==tuple:
			for i in self.code: exec i

scanexec = {}
##########################################################
menu = sv.Menus()
##########################################################  Image Scan Definition: Start

## Name the new scan type
mytreename = 'image'

## Define what menus get displayed ##
mybranches = ['Sample Information','Image Parameters','Image Size','Offsets','Gains']

## Create the menus ##
mytwignames = menu._fullMenu(mybranches,2)  
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {'scan y':(1,1000),'scan x':(1,1000)} ## set any necessary limits

## Make the tree structure from the menus
image_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)

## Append the new tree structure to the list for insertion into the wx widget
treelist.append(image_tree)

## Define the data package that will get sent to the controller
## Note: object oriented programming allows changes made to these
## variables to be carried throughout
class ImagePackage(object):
	'''
	The data package for a vanilla image scan. This class is also subclassed
	by other image packages since like variables are used.
	
	'''
	def __init__(self):
		self.ID = image_tree.data['Sample Information'][sv.ID[2]][0:2]
		self.NAME = image_tree.data['Sample Information'][sv.NAME[2]][0:2]
		self.SAMPLE_BIAS = image_tree.data['Image Parameters'][sv.SAMPLE_BIAS[2]][0:2]
		self.N_READS = image_tree.data['Image Parameters'][sv.N_READS[2]][0:2]
		self.SCAN_DELAY = image_tree.data['Image Parameters'][sv.SCAN_DELAY[2]][0:2]
		self.LINE_DELAY = image_tree.data['Image Parameters'][sv.LINE_DELAY[2]][0:2]
		self.POINT_DELAY = image_tree.data['Image Parameters'][sv.POINT_DELAY[2]][0:2]
		self.ACCEL_WIDTH = image_tree.data['Image Parameters'][sv.ACCEL_WIDTH[2]][0:2]
		self.ACCEL_CURVE = image_tree.data['Image Parameters'][sv.ACCEL_CURVE[2]][0:2]
		self.TOP_DOWN = image_tree.data['Image Parameters'][sv.TOP_DOWN[2]][0:2]
		self.SCAN_Y = image_tree.data['Image Size'][sv.SCAN_Y[2]][0:2]
		self.SCAN_X = image_tree.data['Image Size'][sv.SCAN_X[2]][0:2]
		self.PHYS_X = image_tree.data['Image Size'][sv.PHYS_X[2]][0:2]
		self.PHYS_Y = image_tree.data['Image Size'][sv.PHYS_Y[2]][0:2]
		self.PHYS_STEP = image_tree.data['Image Size'][sv.PHYS_STEP[2]][0:2]
		self.SCAN_RATE = image_tree.data['Image Size'][sv.SCAN_RATE[2]][0:2]
		self.MAX_RATE = image_tree.data['Image Size'][sv.MAX_RATE[2]][0:2]
		self.DAC_STEP = image_tree.data['Image Size'][sv.DAC_STEP[2]][0:2]
		self.DAC_AVGS = image_tree.data['Image Size'][sv.DAC_AVGS[2]][0:2]
		self.XOFF = image_tree.data['Offsets'][sv.XOFF[2]][0:2]
		self.YOFF = image_tree.data['Offsets'][sv.YOFF[2]][0:2]
		self.ZOFF = [0.0,'angstroms']
		self.ZRELATIVE = image_tree.data['Offsets'][sv.ZRELATIVE[2]][0:2]
		self.AUTOZ = image_tree.data['Offsets'][sv.AUTOZ[2]][0:2]
		self.GAIN_XHV = image_tree.data['Gains'][sv.GAIN_XHV[2]][0:2]
		self.GAIN_YHV = image_tree.data['Gains'][sv.GAIN_YHV[2]][0:2]
		self.GAIN_ZHV = image_tree.data['Gains'][sv.GAIN_ZHV[2]][0:2]
		self.GAIN_ZOUT = image_tree.data['Gains'][sv.GAIN_ZOUT[2]][0:2]
		self.GAIN_SERVO = image_tree.data['Gains'][sv.GAIN_SERVO[2]][0:2]
		self.CURR_SENS = image_tree.data['Gains'][sv.CURR_SENS[2]][0:2]
		self.CURR_RISE = image_tree.data['Gains'][sv.CURR_RISE[2]][0:2]
		self.VOLT_GAIN = image_tree.data['Gains'][sv.VOLT_GAIN[2]][0:2]
		self.VOLT_FILTER = image_tree.data['Gains'][sv.VOLT_FILTER[2]][0:2]
		self.CLIENT = socket.gethostname()
		self.TYPE = 'image'
		self.SAVE_SCAN = ws.SAVE_IMAGE
		self.DATETIME = time.strftime("%a %b %d, %Y  %-I:%M:%S %p",time.localtime(time.time()))
		self.STARTTIME = time.time()
		self.UO = UnitOrganizer()
		
	def _complete(self):
		'''
		Chronology-dependent data that gets run at the completion of a scan. May also be used to get
		information about the controller.
		
		'''
		import socket,time
		self.CONTROLLER = socket.gethostname()
		self.ENDTIME = time.time()
		self.ELAPSEDTIME = round(self.ENDTIME - self.STARTTIME,2)
		self.ENDTIME = str(self.ENDTIME) + ' seconds'
		self.STARTTIME = str(round(self.STARTTIME,2)) + ' seconds'
		self.ELAPSEDTIME = str(round(self.ELAPSEDTIME,2))+ ' seconds'

## Create the scan class which instructs the controller on what to do
class ImageScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._checkHardware()
		start_time = time.time()
		
		##set up the bias and offsets before scanning
		if self.im.tip.currentPhysical() != self.im._convertBias(self.package.SAMPLE_BIAS[0]):
			self.im._setTip(self.im._convertBias(self.package.SAMPLE_BIAS[0]),report=True)
		if self.im.xoff.currentPhysical() != self.package.XOFF[0]:
			self.im._moveXOffset(self.package.XOFF[0])
		if self.im.yoff.currentPhysical() != self.package.YOFF[0]:
			self.im._moveYOffset(self.package.YOFF[0])
		if self.package.AUTOZ[0]: self.im._autoZ(self.package.ZRELATIVE[0])
		
		self.im._writeSettings()
		self.im._setXStart() #move piezos to the starting position
		self.im._setYStart()
		self.im._scanDelay()
		while 0 <= self.im.yloc <= self.package.SCAN_Y[0]-1:
			self.im._imageLine(0)
			self.im._sendLine() ##belongs before line advance
			self.im._advanceLine() #move to the next y-position
			#if self.package.LINE_DELAY[0]: self.im._lineDelay()
			#self.im._getNewParameters()
			result = self.im._checkMessages('abort')
			if result: break
		self.im._returnX() #return piezos to the (0,0) position
		self.im._returnY()
		self.im._appendData()
		if not result:
			self.im._saveData() #save the data to disk
		else: self.im._saveData(abort=True)
		self.im._sendFinal() #send the completed scan back to the controller


impkg = ImagePackage() #create a package object
image = ImageScan(impkg) #create a scan object
classlist.append(impkg.__class__) #add the objects to the list
classlist.append(image.__class__)
scanexec[copy(mytreename)] = ScanExecutor(image,impkg)

##########################################################  image Scan Definition: End
##########################################################

mytreename = 'imagewiv'
mybranches = ['Sample Information','Image Parameters','Image Size','IV Parameters','IV Delays','Multi-Z IV','Spectroscopy Locations','Offsets','Gains']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {'scan y':(1,1000),'scan x':(1,1000)}

imiv_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
treelist.append(imiv_tree)

imiv_tree.data['Sample Information'] = image_tree.data['Sample Information']
imiv_tree.data['Image Parameters'] = image_tree.data['Image Parameters']
imiv_tree.data['Image Size'] = image_tree.data['Image Size']
imiv_tree.data['Offsets'] = image_tree.data['Offsets']
imiv_tree.data['Gains'] = image_tree.data['Gains']

class ImIVPackage(ImagePackage):
	'''
	The data package for an image scan that contains a grid of spectroscopy data. Subclasses the
	image package.
	
	'''
	def __init__(self):
		ImagePackage.__init__(self)
		#self.DO_IV = imiv_tree.data['IV Parameters'][sv.DO_IV[2]][0:2]
		self.IV_START = imiv_tree.data['IV Parameters'][sv.IV_START[2]][0:2]
		self.IV_END = imiv_tree.data['IV Parameters'][sv.IV_END[2]][0:2]
		self.IV_READS = imiv_tree.data['IV Parameters'][sv.IV_READS[2]][0:2]
		self.IV_DELAY = imiv_tree.data['IV Delays'][sv.IV_DELAY[2]][0:2]
		self.IV_PREDELAY = imiv_tree.data['IV Delays'][sv.IV_PREDELAY[2]][0:2]
		self.IV_SETDELAY = imiv_tree.data['IV Delays'][sv.IV_SETDELAY[2]][0:2]
		self.IV_MIDDELAY = imiv_tree.data['IV Delays'][sv.IV_MIDDELAY[2]][0:2]
		self.IV_POSTDELAY = imiv_tree.data['IV Delays'][sv.IV_POSTDELAY[2]][0:2]
		self.IV_STEPS = imiv_tree.data['IV Parameters'][sv.IV_STEPS[2]][0:2]
		self.IV_RMPSTP = imiv_tree.data['IV Parameters'][sv.IV_RMPSTP[2]][0:2]
		self.RAMP_HZ = imiv_tree.data['IV Parameters'][sv.RAMP_HZ[2]][0:2]
		self.IV_LIM = imiv_tree.data['IV Parameters'][sv.IV_LIM[2]][0:2]
		self.I_MAX = imiv_tree.data['IV Parameters'][sv.I_MAX[2]][0:2]
		self.I_MIN = imiv_tree.data['IV Parameters'][sv.I_MIN[2]][0:2]
		self.IV_MULTIZ = imiv_tree.data['Multi-Z IV'][sv.IV_MULTIZ[2]][0:2]
		self.IV_Z = (imiv_tree.data['Multi-Z IV']['z0'],imiv_tree.data['Multi-Z IV']['z1'],\
		imiv_tree.data['Multi-Z IV']['z2'],imiv_tree.data['Multi-Z IV']['z3'],imiv_tree.data['Multi-Z IV']['z4'],\
		imiv_tree.data['Multi-Z IV']['z5'],imiv_tree.data['Multi-Z IV']['z6'],imiv_tree.data['Multi-Z IV']['z7'],\
		imiv_tree.data['Multi-Z IV']['z8'])
		self.GRIDX = imiv_tree.data['Spectroscopy Locations'][sv.GRIDX[2]][0:2]
		self.GRIDY = imiv_tree.data['Spectroscopy Locations'][sv.GRIDY[2]][0:2]
		self.STARTX = imiv_tree.data['Spectroscopy Locations'][sv.STARTX[2]][0:2]
		self.STARTY = imiv_tree.data['Spectroscopy Locations'][sv.STARTY[2]][0:2]
		self.ENDX = imiv_tree.data['Spectroscopy Locations'][sv.ENDX[2]][0:2]
		self.ENDY = imiv_tree.data['Spectroscopy Locations'][sv.ENDY[2]][0:2]
		self.CHECKER = imiv_tree.data['Spectroscopy Locations'][sv.CHECKER[2]][0:2]
		self.CLIENT = socket.gethostname()
		self.TYPE = 'imagewiv'
		self.SAVE_SCAN = ws.SAVE_IMAGEWIV
		self.DATETIME = time.strftime("%a %b %d, %Y  %-I:%M:%S %p",time.localtime(time.time()))
		self.STARTTIME = time.time()
		
	def _complete(self):
		'''
		Chronology-dependent data that gets run at the completion of a scan. May also be used to get
		information about the controller.
		
		'''
		import socket,time
		self.CONTROLLER = socket.gethostname()
		self.ENDTIME = time.time()
		self.ELAPSEDTIME = round(self.ENDTIME - self.STARTTIME,2)
		self.ENDTIME = str(self.ENDTIME) + ' seconds'
		self.STARTTIME = str(round(self.STARTTIME,2)) + ' seconds'
		self.ELAPSEDTIME = str(round(self.ELAPSEDTIME,2))+ ' seconds'

class ImIVScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._checkHardware()
		start_time = time.time()
		
		#if self.package.DO_IV[0]:
		self.im._initSpectroscopy()

		if self.im.tip.currentPhysical() != self.im._convertBias(self.package.SAMPLE_BIAS[0]):
			self.im._setTip(self.im._convertBias(self.package.SAMPLE_BIAS[0]),report=True)
		if self.im.xoff.currentPhysical() != self.package.XOFF[0]:
			self.im._moveXOffset(self.package.XOFF[0])
		if self.im.yoff.currentPhysical() != self.package.YOFF[0]:
			self.im._moveYOffset(self.package.YOFF[0])
		if self.package.AUTOZ[0]: self.im._autoZ(self.package.ZRELATIVE[0])
		
		self.im._writeSettings()
		self.im._setXStart()
		self.im._setYStart()
		self.im._scanDelay()
		while 0 <= self.im.yloc <= self.package.SCAN_Y[0]-1:
			self.im._imageLineWSpec()
			self.im._sendLine() ##belongs before line advance
			self.im._advanceLine()
			self.im._getSpecLoc()
			#if self.package.LINE_DELAY[0]: self.im._lineDelay()
			#self.im._getNewParameters()
			result = self.im._checkMessages('abort')
			if result: break
		self.im._returnX()
		self.im._returnY()
		self.im._appendData()
		if not result:
			self.im._saveData()
		else: self.im._saveData(abort=True)
		self.im._sendFinal()


imivpkg = ImIVPackage()
imagewiv = ImIVScan(imivpkg)
classlist.append(imivpkg.__class__)
classlist.append(imagewiv.__class__)
scanexec[copy(mytreename)] = ScanExecutor(imagewiv,imivpkg)

##########################################################
##########################################################

mytreename = 'imagewiz'
mybranches = ['Sample Information','Image Parameters','Image Size','IZ Parameters','IZ Delays','Spectroscopy Locations','Offsets','Gains']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {'scan y':(1,1000),'scan x':(1,1000)}

imiz_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
treelist.append(imiz_tree)

imiz_tree.data['Sample Information'] = image_tree.data['Sample Information']
imiz_tree.data['Image Parameters'] = image_tree.data['Image Parameters']
imiz_tree.data['Image Size'] = image_tree.data['Image Size']
imiz_tree.data['Offsets'] = image_tree.data['Offsets']
imiz_tree.data['Gains'] = image_tree.data['Gains']
imiz_tree.data['Spectroscopy Locations'] = imiv_tree.data['Spectroscopy Locations']

class ImIZPackage(ImagePackage):
	'''
	The data package for an image scan that contains a grid of spectroscopy data. Subclasses the
	image package.
	
	'''
	def __init__(self):
		ImagePackage.__init__(self)
		self.IZ_START = imiz_tree.data['IZ Parameters'][sv.IZ_START[2]][0:2]
		self.IZ_END = imiz_tree.data['IZ Parameters'][sv.IZ_END[2]][0:2]
		self.IZ_READS = imiz_tree.data['IZ Parameters'][sv.IZ_READS[2]][0:2]
		self.IZ_STEPS = imiz_tree.data['IZ Parameters'][sv.IZ_STEPS[2]][0:2]
		self.IZ_DELAY = imiz_tree.data['IZ Delays'][sv.IZ_DELAY[2]][0:2]
		self.IZ_SETDELAY = imiz_tree.data['IZ Delays'][sv.IZ_SETDELAY[2]][0:2]
		self.IZ_POSTDELAY = imiz_tree.data['IZ Delays'][sv.IZ_POSTDELAY[2]][0:2]
		self.GRIDX = imiz_tree.data['Spectroscopy Locations'][sv.GRIDX[2]][0:2]
		self.GRIDY = imiz_tree.data['Spectroscopy Locations'][sv.GRIDY[2]][0:2]
		self.STARTX = imiz_tree.data['Spectroscopy Locations'][sv.STARTX[2]][0:2]
		self.STARTY = imiz_tree.data['Spectroscopy Locations'][sv.STARTY[2]][0:2]
		self.ENDX = imiz_tree.data['Spectroscopy Locations'][sv.ENDX[2]][0:2]
		self.ENDY = imiz_tree.data['Spectroscopy Locations'][sv.ENDY[2]][0:2]
		self.CHECKER = imiz_tree.data['Spectroscopy Locations'][sv.CHECKER[2]][0:2]
		self.CLIENT = socket.gethostname()
		self.TYPE = 'imagewiz'
		self.SAVE_SCAN = ws.SAVE_IMAGEWIV
		self.DATETIME = time.strftime("%a %b %d, %Y  %-I:%M:%S %p",time.localtime(time.time()))
		self.STARTTIME = time.time()
		
	def _complete(self):
		'''
		Chronology-dependent data that gets run at the completion of a scan. May also be used to get
		information about the controller.
		
		'''
		import socket,time
		self.CONTROLLER = socket.gethostname()
		self.ENDTIME = time.time()
		self.ELAPSEDTIME = round(self.ENDTIME - self.STARTTIME,2)
		self.ENDTIME = str(self.ENDTIME) + ' seconds'
		self.STARTTIME = str(round(self.STARTTIME,2)) + ' seconds'
		self.ELAPSEDTIME = str(round(self.ELAPSEDTIME,2))+ ' seconds'

class ImIZScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._checkHardware()
		start_time = time.time()
		
		#if self.package.DO_IV[0]:
		self.im._initSpectroscopy()

		if self.im.tip.currentPhysical() != self.im._convertBias(self.package.SAMPLE_BIAS[0]):
			self.im._setTip(self.im._convertBias(self.package.SAMPLE_BIAS[0]),report=True)
		if self.im.xoff.currentPhysical() != self.package.XOFF[0]:
			self.im._moveXOffset(self.package.XOFF[0])
		if self.im.yoff.currentPhysical() != self.package.YOFF[0]:
			self.im._moveYOffset(self.package.YOFF[0])
		if self.package.AUTOZ[0]: self.im._autoZ(self.package.ZRELATIVE[0])
		
		self.im._writeSettings()
		self.im._setXStart()
		self.im._setYStart()
		self.im._scanDelay()
		while 0 <= self.im.yloc <= self.package.SCAN_Y[0]-1:
			self.im._imageLineWSpec()
			self.im._sendLine() ##belongs before line advance
			self.im._advanceLine()
			self.im._getSpecLoc()
			if self.package.LINE_DELAY[0]: self.im._lineDelay()
			#self.im._getNewParameters()
			result = self.im._checkMessages('abort')
			if result: break
		self.im._returnX()
		self.im._returnY()
		self.im._appendData()
		if not result:
			self.im._saveData()
		else: self.im._saveData(abort=True)
		self.im._sendFinal()


imizpkg = ImIZPackage()
imagewiz = ImIZScan(imizpkg)
classlist.append(imizpkg.__class__)
classlist.append(imagewiz.__class__)
scanexec[copy(mytreename)] = ScanExecutor(imagewiz,imizpkg)

##########################################################
##########################################################

mytreename = 'imagewzv'
mybranches = ['Sample Information','Image Parameters','Image Size','ZV Parameters','ZV Delays','Spectroscopy Locations','Offsets','Gains']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {'scan y':(1,1000),'scan x':(1,1000)}

imzv_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
treelist.append(imzv_tree)

imzv_tree.data['Sample Information'] = image_tree.data['Sample Information']
imzv_tree.data['Image Parameters'] = image_tree.data['Image Parameters']
imzv_tree.data['Image Size'] = image_tree.data['Image Size']
imzv_tree.data['Offsets'] = image_tree.data['Offsets']
imzv_tree.data['Gains'] = image_tree.data['Gains']
imzv_tree.data['Spectroscopy Locations'] = imiv_tree.data['Spectroscopy Locations']

class ImZVPackage(ImagePackage):
	'''
	The data package for an image scan that contains a grid of spectroscopy data. Subclasses the
	image package.
	
	'''
	def __init__(self):
		ImagePackage.__init__(self)
		self.ZV_READS = imzv_tree.data['ZV Parameters'][sv.ZV_READS[2]][0:2]
		self.ZV_DELAY = imzv_tree.data['ZV Delays'][sv.ZV_DELAY[2]][0:2]
		self.ZV_PREDELAY = imzv_tree.data['ZV Delays'][sv.ZV_PREDELAY[2]][0:2]
		self.ZV_MIDDELAY = imzv_tree.data['ZV Delays'][sv.ZV_MIDDELAY[2]][0:2]
		self.ZV_POSTDELAY = imzv_tree.data['ZV Delays'][sv.ZV_POSTDELAY[2]][0:2]
		self.ZV_START = imzv_tree.data['ZV Parameters'][sv.ZV_START[2]][0:2]
		self.ZV_END = imzv_tree.data['ZV Parameters'][sv.ZV_END[2]][0:2]
		self.ZV_STEPS = imzv_tree.data['ZV Parameters'][sv.ZV_STEPS[2]][0:2]
		self.GRIDX = imzv_tree.data['Spectroscopy Locations'][sv.GRIDX[2]][0:2]
		self.GRIDY = imzv_tree.data['Spectroscopy Locations'][sv.GRIDY[2]][0:2]
		self.STARTX = imzv_tree.data['Spectroscopy Locations'][sv.STARTX[2]][0:2]
		self.STARTY = imzv_tree.data['Spectroscopy Locations'][sv.STARTY[2]][0:2]
		self.ENDX = imzv_tree.data['Spectroscopy Locations'][sv.ENDX[2]][0:2]
		self.ENDY = imzv_tree.data['Spectroscopy Locations'][sv.ENDY[2]][0:2]
		self.CHECKER = imzv_tree.data['Spectroscopy Locations'][sv.CHECKER[2]][0:2]
		self.CLIENT = socket.gethostname()
		self.TYPE = 'imagewzv'
		self.SAVE_SCAN = ws.SAVE_IMAGEWIV
		self.DATETIME = time.strftime("%a %b %d, %Y  %-I:%M:%S %p",time.localtime(time.time()))
		self.STARTTIME = time.time()
		
	def _complete(self):
		'''
		Chronology-dependent data that gets run at the completion of a scan. May also be used to get
		information about the controller.
		
		'''
		import socket,time
		self.CONTROLLER = socket.gethostname()
		self.ENDTIME = time.time()
		self.ELAPSEDTIME = round(self.ENDTIME - self.STARTTIME,2)
		self.ENDTIME = str(self.ENDTIME) + ' seconds'
		self.STARTTIME = str(round(self.STARTTIME,2)) + ' seconds'
		self.ELAPSEDTIME = str(round(self.ELAPSEDTIME,2))+ ' seconds'

class ImZVScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._checkHardware()
		start_time = time.time()
		
		#if self.package.DO_IV[0]:
		self.im._initSpectroscopy()

		if self.im.tip.currentPhysical() != self.im._convertBias(self.package.SAMPLE_BIAS[0]):
			self.im._setTip(self.im._convertBias(self.package.SAMPLE_BIAS[0]),report=True)
		if self.im.xoff.currentPhysical() != self.package.XOFF[0]:
			self.im._moveXOffset(self.package.XOFF[0])
		if self.im.yoff.currentPhysical() != self.package.YOFF[0]:
			self.im._moveYOffset(self.package.YOFF[0])
		if self.package.AUTOZ[0]: self.im._autoZ(self.package.ZRELATIVE[0])
		
		self.im._writeSettings()
		self.im._setXStart()
		self.im._setYStart()
		self.im._scanDelay()
		while 0 <= self.im.yloc <= self.package.SCAN_Y[0]-1:
			self.im._imageLineWSpec()
			self.im._sendLine() ##belongs before line advance
			self.im._advanceLine()
			self.im._getSpecLoc()
			if self.package.LINE_DELAY[0]: self.im._lineDelay()
			#self.im._getNewParameters()
			result = self.im._checkMessages('abort')
			if result: break
		self.im._returnX()
		self.im._returnY()
		self.im._appendData()
		if not result:
			self.im._saveData()
		else: self.im._saveData(abort=True)
		self.im._sendFinal()


imzvpkg = ImZVPackage()
imagewzv = ImZVScan(imzvpkg)
classlist.append(imzvpkg.__class__)
classlist.append(imagewzv.__class__)
scanexec[copy(mytreename)] = ScanExecutor(imagewzv,imzvpkg)

##########################################################
##########################################################

mytreename = 'multibias'
mybranches = ['Sample Information','Image Parameters','Image Size','Multiple Bias','Offsets','Gains']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {'scan y':(1,1000),'scan x':(1,1000)}

multibias_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
treelist.append(multibias_tree)
multibias_tree.data['Sample Information'] = image_tree.data['Sample Information']
multibias_tree.data['Image Parameters'] = image_tree.data['Image Parameters']
multibias_tree.data['Image Size'] = image_tree.data['Image Size']
multibias_tree.data['Offsets'] = image_tree.data['Offsets']
multibias_tree.data['Gains'] = image_tree.data['Gains']
multibias_tree.data['Multiple Bias'][sv.BIAS_STEPS[0][2]] = image_tree.data['Image Parameters'][sv.SAMPLE_BIAS[2]]

class MultiPackage(ImagePackage):
	def __init__(self):
		ImagePackage.__init__(self)
		self.N_BIAS_STEPS = multibias_tree.data['Multiple Bias'][sv.N_BIAS_STEPS[2]][0:2]
		self.BIAS_STEPS = [multibias_tree.data['Multiple Bias'][sv.BIAS_STEPS[0][2]],\
		multibias_tree.data['Multiple Bias'][sv.BIAS_STEPS[1][2]],multibias_tree.data['Multiple Bias'][sv.BIAS_STEPS[2][2]],\
		multibias_tree.data['Multiple Bias'][sv.BIAS_STEPS[3][2]],multibias_tree.data['Multiple Bias'][sv.BIAS_STEPS[4][2]],\
		multibias_tree.data['Multiple Bias'][sv.BIAS_STEPS[5][2]],multibias_tree.data['Multiple Bias'][sv.BIAS_STEPS[6][2]],\
		multibias_tree.data['Multiple Bias'][sv.BIAS_STEPS[7][2]]]
		self.CLIENT = socket.gethostname()
		self.TYPE = 'multibias'
		self.SAVE_SCAN = ws.SAVE_MULTIBIAS
		self.DATETIME = time.strftime("%a %b %d, %Y  %-I:%M:%S %p",time.localtime(time.time()))
		self.STARTTIME = time.time()
		
	def _complete(self):
		'''
		Chronology-dependent data that gets run at the completion of a scan. May also be used to get
		information about the controller.
		
		'''
		import socket,time
		self.CONTROLLER = socket.gethostname()
		self.ENDTIME = time.time()
		self.ELAPSEDTIME = round(self.ENDTIME - self.STARTTIME,2)
		self.ENDTIME = str(self.ENDTIME) + ' seconds'
		self.STARTTIME = str(round(self.STARTTIME,2)) + ' seconds'
		self.ELAPSEDTIME = str(round(self.ELAPSEDTIME,2))+ ' seconds'

class MultiScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._checkHardware()
		start_time = time.time()

		if self.im.tip.currentPhysical() != self.im._convertBias(self.package.SAMPLE_BIAS[0]):
			self.im._setTip(self.im._convertBias(self.package.SAMPLE_BIAS[0]),report=True)
		if self.im.xoff.currentPhysical() != self.package.XOFF[0]:
			self.im._moveXOffset(self.package.XOFF[0])
		if self.im.yoff.currentPhysical() != self.package.YOFF[0]:
			self.im._moveYOffset(self.package.YOFF[0])
		if self.package.AUTOZ[0]: self.im._autoZ(self.package.ZRELATIVE[0])
		
		self.im._writeSettings()
		self.im._setXStart()
		self.im._setYStart()
		self.im._scanDelay()
		while 0 <= self.im.yloc <= self.package.SCAN_Y[0]-1:
			for i in range(self.package.N_BIAS_STEPS[0]+1):
				self.im._setTip(self.im._convertBias(self.package.BIAS_STEPS[i][0]))
				self.im._imageLine(i)
			self.im._sendLine() ##belongs before line advance
			self.im._advanceLine()
			if self.package.LINE_DELAY[0]: self.im._lineDelay()
			#self.im._getNewParameters()
			result = self.im._checkMessages('abort')
			if result: break
		self.im._returnX()
		self.im._returnY()
		self.im._appendData()
		if not result:
			self.im._saveData()
		else: self.im._saveData(abort=True)
		self.im._sendFinal()


pkgmulti = MultiPackage()
imagemulti = MultiScan(pkgmulti)
classlist.append(pkgmulti.__class__)
classlist.append(imagemulti.__class__)
scanexec[copy(mytreename)] = ScanExecutor(imagemulti,pkgmulti)

##########################################################
##########################################################

mytreename = 'presets'
mybranches = ['Bias','Offsets','Gains']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {}

presets_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
#connect any like variables that should be simultaneously changed in other scans
presets_tree.data['Bias']['sample bias'] = image_tree.data['Image Parameters']['sample bias']
presets_tree.data['Offsets'] = image_tree.data['Offsets']
presets_tree.data['Gains'] = image_tree.data['Gains']
treelist.append(presets_tree)

class PresetsPackage(ImagePackage):
	def __init__(self):
		ImagePackage.__init__(self)
		self.TYPE = 'presets'
		
	def _complete(self):
		pass

class PresetsScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._releaseHold()
		if self.im.tip.currentPhysical() != self.im._convertBias(self.package.SAMPLE_BIAS[0]):
				self.im._setTip(self.im._convertBias(self.package.SAMPLE_BIAS[0]),report=True)
		if self.im.xoff.currentPhysical() != self.package.XOFF[0]:
			self.im._moveXOffset(self.package.XOFF[0])
		if self.im.yoff.currentPhysical() != self.package.YOFF[0]:
			self.im._moveYOffset(self.package.YOFF[0])
		#if self.im.zoff.currentPhysical() != self.package.ZRELATIVE[0]:
			#self.im._moveZOffset(self.package.ZRELATIVE[0])
		if self.package.AUTOZ[0]: self.im._autoZ(self.package.ZRELATIVE[0])
		self.im._writeSettings()
	
pspkg = PresetsPackage()
presets = PresetsScan(pspkg)
classlist.append(pspkg.__class__)
classlist.append(presets.__class__)
scanexec[copy(mytreename)] = ScanExecutor(presets,pspkg)

#########################################################

mytreename = 'approach'
mybranches = ['Approach Settings']
mytwignames = (['center','cutoff','sample bias'],)
mytwigvalues = ([-3.,9.,-4.],)
mytwigunits = (['volts','volts','volts'],)
mytwigdescr = (['','',''],)
mytwigcell = (['000','000','000'],)
mytwiglimits = {'cutoff':(1,9.9)}

approach_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
treelist.append(approach_tree)
approach_tree.data['Approach Settings']['sample bias'] = imiv_tree.data['Image Parameters']['sample bias']

class ApproachPackage(object):
	def __init__(self):
		self.NAME = ['approach']
		self.CENTER = approach_tree.data['Approach Settings']['center']
		self.CUTOFF = approach_tree.data['Approach Settings']['cutoff']
		self.SAMPLE_BIAS = approach_tree.data['Approach Settings']['sample bias']
		self.TYPE = 'approach'
		
	def _complete(self):
		'''
		Chronology-dependent data that gets run at the completion of a scan. May also be used to get
		information about the controller.
		
		'''
		pass

class ApproachScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._checkHardware()
		self.im._setTip(self.im._convertBias(self.package.SAMPLE_BIAS[0]),report=True)
		self.im._approachSample()

pkgapp = ApproachPackage()
approach = ApproachScan(pkgapp)
classlist.append(pkgapp.__class__)
classlist.append(approach.__class__)
scanexec[copy(mytreename)] = ScanExecutor(approach,pkgapp)

##########################################################
##########################################################

mytreename = 'manual approach'
mybranches = ['Bias','Offsets','Gains']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {}

manualapp_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
#connect any like variables that should be simultaneously changed in other scans
manualapp_tree.data['Bias']['sample bias'] = image_tree.data['Image Parameters']['sample bias']
manualapp_tree.data['Offsets'] = image_tree.data['Offsets']
manualapp_tree.data['Gains'] = image_tree.data['Gains']
treelist.append(manualapp_tree)

class ManualAppPackage(ImagePackage):
	def __init__(self):
		ImagePackage.__init__(self)
		self.TYPE = 'manual approach'
		
	def _complete(self):
		pass

class ManualAppScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._releaseHold()
		if self.im.tip.currentPhysical() != self.im._convertBias(self.package.SAMPLE_BIAS[0]):
				self.im._setTip(self.im._convertBias(self.package.SAMPLE_BIAS[0]),report=True)
		if self.im.xoff.currentPhysical() != self.package.XOFF[0]:
			self.im._moveXOffset(self.package.XOFF[0])
		if self.im.yoff.currentPhysical() != self.package.YOFF[0]:
			self.im._moveYOffset(self.package.YOFF[0])
		#if self.im.zoff.currentPhysical() != self.package.ZRELATIVE[0]:
			#self.im._moveZOffset(self.package.ZRELATIVE[0])
		if self.package.AUTOZ[0]: self.im._autoZ(self.package.ZRELATIVE[0])
		self.im._writeSettings()
		self.im._manualApproach()
	
mppkg = ManualAppPackage()
manualapp = ManualAppScan(mppkg)
classlist.append(mppkg.__class__)
classlist.append(manualapp.__class__)
scanexec[copy(mytreename)] = ScanExecutor(manualapp,mppkg)
scanexec[copy(mytreename)].code = ['from client.manualapp import ManualApproach','parent.manualapp = ManualApproach(parent,\'Approach\')']

#########################################################
##########################################################

mytreename = 'continuous'
mybranches = ['Sample Information','Image Parameters','Image Size','Offsets','Gains']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {'scan y':(1,1000),'scan x':(1,1000)}

continuous_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
treelist.append(continuous_tree)

continuous_tree.data['Sample Information'] = image_tree.data['Sample Information']
continuous_tree.data['Image Parameters'] = image_tree.data['Image Parameters']
continuous_tree.data['Image Size'] = image_tree.data['Image Size']
continuous_tree.data['Offsets'] = image_tree.data['Offsets']
continuous_tree.data['Gains'] = image_tree.data['Gains']


class ContinuousPackage(ImagePackage):
	def __init__(self):
		ImagePackage.__init__(self)
		self.TYPE = 'continuous'
		self.SAVE_SCAN = ws.SAVE_CONTINUOUS
		
	def _complete(self):
		'''
		Chronology-dependent data that gets run at the completion of a scan. May also be used to get
		information about the controller.
		
		'''
		import socket,time
		self.CONTROLLER = socket.gethostname()
		self.ENDTIME = time.time()
		self.ELAPSEDTIME = round(self.ENDTIME - self.STARTTIME,2)
		self.ENDTIME = str(self.ENDTIME) + ' seconds'
		#self.STARTTIME = str(round(self.STARTTIME,2)) + ' seconds'
		self.ELAPSEDTIME = str(round(self.ELAPSEDTIME,2))+ ' seconds'

class ContinuousScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._checkHardware()
		start_time = time.time()

		if self.im.tip.currentPhysical() != self.im._convertBias(self.package.SAMPLE_BIAS[0]):
			self.im._setTip(self.im._convertBias(self.package.SAMPLE_BIAS[0]),report=True)
		if self.im.xoff.currentPhysical() != self.package.XOFF[0]:
			self.im._moveXOffset(self.package.XOFF[0])
		if self.im.yoff.currentPhysical() != self.package.YOFF[0]:
			self.im._moveYOffset(self.package.YOFF[0])
		if self.package.AUTOZ[0]: self.im._autoZ(self.package.ZRELATIVE[0])
		
		self.im._writeSettings()
		self.im._setXStart()
		self.im.package.TOP_DOWN[0]=0
		self.im._setYStart()
		self.im._scanDelay()
		fcapture = False
		while 1:
			self.im.package.TOP_DOWN[0]=0
			while self.im.yloc <= self.package.SCAN_Y[0]-1:
				self.im._imageLine(0)
				self.im._sendLine() ##belongs before line advance
				self.im._advanceLine()
				if self.package.LINE_DELAY[0]: self.im._lineDelay()
				#self.im._getNewParameters()
				save = self.im._checkMessages('capture')
				if save:
					self.im._saveData(bypass=True)
				save = self.im._checkMessages('fcapture')
				if save: fcapture = True
				result = self.im._checkMessages('abort',clearq=True)
				if result: break
			if result: break
			if fcapture:
				self.im._saveData(bypass=True)
				fcapture = False
			self.im.package.TOP_DOWN[0]=1
			while self.im.yloc > 0:
				#self.im._withdrawLine()
				self.im._advanceLine()
				self.im._imageLine(0)
				self.im._sendLine() ##belongs after withdraw
				if self.package.LINE_DELAY[0]: self.im._lineDelay()
				#self.im._getNewParameters()
				save = self.im._checkMessages('capture')
				if save:
					self.im._saveData(bypass=True)
				save = self.im._checkMessages('fcapture')
				if save: fcapture = True
				result = self.im._checkMessages('abort',clearq=True)
				if result: break
			if result: break
			if fcapture:
				self.im._saveData(bypass=True)
				fcapture = False
		self.im._returnX()
		self.im._returnY()
		self.im._appendData()
		self.im._saveData(abort=True)
		self.im._sendFinal()


pkgco = ContinuousPackage()
continuous = ContinuousScan(pkgco)
classlist.append(pkgco.__class__)
classlist.append(continuous.__class__)
scanexec[copy(mytreename)] = ScanExecutor(continuous,pkgco)

###########################################################
##########################################################

mytreename = 'singleiv'
mybranches = ['Sample Information','Bias','IV Parameters','IV Delays','Multi-Z IV','Offsets','Gains']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {'scan y':(1,1000),'scan x':(1,1000)}

siv_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
treelist.append(siv_tree)
siv_tree.data['Sample Information'] = image_tree.data['Sample Information']
siv_tree.data['IV Parameters'] = imiv_tree.data['IV Parameters']
siv_tree.data['IV Delays'] = imiv_tree.data['IV Delays']
siv_tree.data['Bias']['sample bias'] = image_tree.data['Image Parameters']['sample bias']
siv_tree.data['Multi-Z IV'] = imiv_tree.data['Multi-Z IV']
siv_tree.data['Offsets'] = image_tree.data['Offsets']
siv_tree.data['Gains'] = image_tree.data['Gains']
siv_tree.data['IV Parameters'][sv.SAMPLE_BIAS[2]] = image_tree.data['Image Parameters'][sv.SAMPLE_BIAS[2]]

class sivPackage(ImIVPackage):
	def __init__(self):
		ImIVPackage.__init__(self)
		self.CLIENT = socket.gethostname()
		self.TYPE = 'singleiv'
		self.SAVE_SCAN = ws.SAVE_SINGLEIV
		self.DATETIME = time.strftime("%a %b %d, %Y  %-I:%M:%S %p",time.localtime(time.time()))
		self.STARTTIME = time.time()
		
	def _complete(self):
		'''
		Chronology-dependent data that gets run at the completion of a scan. May also be used to get
		information about the controller.
		
		'''
		import socket,time
		self.CONTROLLER = socket.gethostname()
		self.ENDTIME = time.time()
		self.ELAPSEDTIME = round(self.ENDTIME - self.STARTTIME,2)
		self.ENDTIME = str(self.ENDTIME) + ' seconds'
		self.STARTTIME = str(round(self.STARTTIME,2)) + ' seconds'
		self.ELAPSEDTIME = str(round(self.ELAPSEDTIME,2))+ ' seconds'

class sivScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._checkHardware()
		start_time = time.time()
		
		self.im._initSpectroscopy()

		if self.im.tip.currentPhysical() != self.im._convertBias(self.package.SAMPLE_BIAS[0]):
			self.im._setTip(self.im._convertBias(self.package.SAMPLE_BIAS[0]),report=True)
		if self.im.xoff.currentPhysical() != self.package.XOFF[0]:
			self.im._moveXOffset(self.package.XOFF[0])
		if self.im.yoff.currentPhysical() != self.package.YOFF[0]:
			self.im._moveYOffset(self.package.YOFF[0])
		if self.package.AUTOZ[0]: self.im._autoZ(self.package.ZRELATIVE[0])
		self.im._writeSettings()
		
		if not self.package.IV_LIM[0]:
			self.im._doIV(0,0)
		else: self.im._doIVLimit(0,0,self.package.I_MIN[0],self.package.I_MAX[0])
		self.im._appendData()
		self.im._sendFinal()
		self.im._saveData()

pkgsiv = sivPackage()
singleiv = sivScan(pkgsiv)
classlist.append(pkgsiv.__class__)
classlist.append(singleiv.__class__)
scanexec[copy(mytreename)] = ScanExecutor(singleiv,pkgsiv)

#########################################################
##########################################################

mytreename = 'singleiz'
mybranches = ['Sample Information','Bias','IZ Parameters','IZ Delays','Offsets','Gains']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {'scan y':(1,1000),'scan x':(1,1000)}

siz_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
treelist.append(siz_tree)
siz_tree.data['Sample Information'] = image_tree.data['Sample Information']
siz_tree.data['Bias']['sample bias'] = image_tree.data['Image Parameters']['sample bias']
siz_tree.data['Offsets'] = image_tree.data['Offsets']
siz_tree.data['Gains'] = image_tree.data['Gains']
siz_tree.data['IZ Parameters'] = imiz_tree.data['IZ Parameters']
siz_tree.data['IZ Delays'] = imiz_tree.data['IZ Delays']

class sizPackage(ImIVPackage):
	def __init__(self):
		ImagePackage.__init__(self)
		self.IZ_READS = siz_tree.data['IZ Parameters'][sv.IZ_READS[2]][0:2]
		self.IZ_DELAY = siz_tree.data['IZ Delays'][sv.IZ_DELAY[2]][0:2]
		self.IZ_SETDELAY = siz_tree.data['IZ Delays'][sv.IZ_SETDELAY[2]][0:2]
		self.IZ_POSTDELAY = siz_tree.data['IZ Delays'][sv.IZ_POSTDELAY[2]][0:2]
		self.IZ_START = siz_tree.data['IZ Parameters'][sv.IZ_START[2]][0:2]
		self.IZ_END = siz_tree.data['IZ Parameters'][sv.IZ_END[2]][0:2]
		self.IZ_STEPS = siz_tree.data['IZ Parameters'][sv.IZ_STEPS[2]][0:2]
		self.CLIENT = socket.gethostname()
		self.TYPE = 'singleiz'
		self.SAVE_SCAN = ws.SAVE_SINGLEIZ
		self.DATETIME = time.strftime("%a %b %d, %Y  %-I:%M:%S %p",time.localtime(time.time()))
		self.STARTTIME = time.time()
		
	def _complete(self):
		'''
		Chronology-dependent data that gets run at the completion of a scan. May also be used to get
		information about the controller.
		
		'''
		import socket,time
		self.CONTROLLER = socket.gethostname()
		self.ENDTIME = time.time()
		self.ELAPSEDTIME = round(self.ENDTIME - self.STARTTIME,2)
		self.ENDTIME = str(self.ENDTIME) + ' seconds'
		self.STARTTIME = str(round(self.STARTTIME,2)) + ' seconds'
		self.ELAPSEDTIME = str(round(self.ELAPSEDTIME,2))+ ' seconds'

class sizScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._checkHardware()
		start_time = time.time()

		if self.im.tip.currentPhysical() != self.im._convertBias(self.package.SAMPLE_BIAS[0]):
			self.im._setTip(self.im._convertBias(self.package.SAMPLE_BIAS[0]),report=True)
		if self.im.xoff.currentPhysical() != self.package.XOFF[0]:
			self.im._moveXOffset(self.package.XOFF[0])
		if self.im.yoff.currentPhysical() != self.package.YOFF[0]:
			self.im._moveYOffset(self.package.YOFF[0])
		if self.package.AUTOZ[0]: self.im._autoZ(self.package.ZRELATIVE[0])
		self.im._writeSettings()
		
		self.im._doIZ(0,0)
		self.im._appendData()
		self.im._sendFinal()
		self.im._saveData()

pkgsiz = sizPackage()
singleiz = sizScan(pkgsiz)
classlist.append(pkgsiz.__class__)
classlist.append(singleiz.__class__)
scanexec[copy(mytreename)] = ScanExecutor(singleiz,pkgsiz)

##########################################################
##########################################################

mytreename = 'singlezv'
mybranches = ['Sample Information','Bias','ZV Parameters','ZV Delays','Offsets','Gains']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {}

szv_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
treelist.append(szv_tree)
szv_tree.data['Sample Information'] = image_tree.data['Sample Information']
szv_tree.data['Offsets'] = image_tree.data['Offsets']
szv_tree.data['Gains'] = image_tree.data['Gains']
szv_tree.data['Bias']['sample bias'] = image_tree.data['Image Parameters']['sample bias']
szv_tree.data['ZV Parameters'] = imzv_tree.data['ZV Parameters']
szv_tree.data['ZV Delays'] = imzv_tree.data['ZV Delays']

class szvPackage(ImIVPackage):
	def __init__(self):
		ImagePackage.__init__(self)
		self.ZV_READS = szv_tree.data['ZV Parameters'][sv.ZV_READS[2]][0:2]
		self.ZV_DELAY = szv_tree.data['ZV Delays'][sv.ZV_DELAY[2]][0:2]
		self.ZV_PREDELAY = szv_tree.data['ZV Delays'][sv.ZV_PREDELAY[2]][0:2]
		self.ZV_MIDDELAY = szv_tree.data['ZV Delays'][sv.ZV_MIDDELAY[2]][0:2]
		self.ZV_POSTDELAY = szv_tree.data['ZV Delays'][sv.ZV_POSTDELAY[2]][0:2]
		self.ZV_START = szv_tree.data['ZV Parameters'][sv.ZV_START[2]][0:2]
		self.ZV_END = szv_tree.data['ZV Parameters'][sv.ZV_END[2]][0:2]
		self.ZV_STEPS = szv_tree.data['ZV Parameters'][sv.ZV_STEPS[2]][0:2]
		self.CLIENT = socket.gethostname()
		self.TYPE = 'singlezv'
		self.SAVE_SCAN = ws.SAVE_SINGLEZV
		self.DATETIME = time.strftime("%a %b %d, %Y  %-I:%M:%S %p",time.localtime(time.time()))
		self.STARTTIME = time.time()
		
	def _complete(self):
		'''
		Chronology-dependent data that gets run at the completion of a scan. May also be used to get
		information about the controller.
		
		'''
		import socket,time
		self.CONTROLLER = socket.gethostname()
		self.ENDTIME = time.time()
		self.ELAPSEDTIME = round(self.ENDTIME - self.STARTTIME,2)
		self.ENDTIME = str(self.ENDTIME) + ' seconds'
		self.STARTTIME = str(round(self.STARTTIME,2)) + ' seconds'
		self.ELAPSEDTIME = str(round(self.ELAPSEDTIME,2))+ ' seconds'

class szvScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._checkHardware()
		start_time = time.time()

		if self.im.tip.currentPhysical() != self.im._convertBias(self.package.SAMPLE_BIAS[0]):
			self.im._setTip(self.im._convertBias(self.package.SAMPLE_BIAS[0]),report=True)
		if self.im.xoff.currentPhysical() != self.package.XOFF[0]:
			self.im._moveXOffset(self.package.XOFF[0])
		if self.im.yoff.currentPhysical() != self.package.YOFF[0]:
			self.im._moveYOffset(self.package.YOFF[0])
		if self.package.AUTOZ[0]: self.im._autoZ(self.package.ZRELATIVE[0])
		self.im._writeSettings()
	
		self.im._doZV(0,0)
		self.im._appendData()
		self.im._sendFinal()
		self.im._saveData()

pkgszv = szvPackage()
singlezv = szvScan(pkgszv)
classlist.append(pkgszv.__class__)
classlist.append(singlezv.__class__)
scanexec[copy(mytreename)] = ScanExecutor(singlezv,pkgszv)

##########################################################
##########################################################

mytreename = 'recovery'
mybranches = ['Bias','Offsets']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {}

recovery_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
#connect any like variables that should be simultaneously changed in other scans
recovery_tree.data['Bias']['sample bias'] = image_tree.data['Image Parameters']['sample bias']
recovery_tree.data['Offsets'] = image_tree.data['Offsets']
treelist.append(recovery_tree)

class RecoveryPackage(ImagePackage):
	def __init__(self):
		ImagePackage.__init__(self)
		self.TYPE = 'recovery'
		
	def _complete(self):
		pass

class RecoveryScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._restoreSettings()
		self.im._sendFinal()
	
	
rcvpkg = RecoveryPackage()
recovery = RecoveryScan(rcvpkg)
classlist.append(rcvpkg.__class__)
classlist.append(recovery.__class__)
scanexec[copy(mytreename)] = ScanExecutor(recovery,rcvpkg)

#########################################################
##########################################################

mytreename = 'zero zoff'
mybranches = ['Bias']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {}

zero_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
#connect any like variables that should be simultaneously changed in other scans
zero_tree.data['Bias']['sample bias'] = image_tree.data['Image Parameters']['sample bias']
treelist.append(zero_tree)

class ZeroPackage(ImagePackage):
	def __init__(self):
		ImagePackage.__init__(self)
		self.TYPE = 'zero zoff'
		
	def _complete(self):
		pass

class ZeroScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._retractTip()
		self.im._moveZOffset(0.0,volts=True)
		self.im._sweepTip()
		
	
	
zeropkg = ZeroPackage()
zero = ZeroScan(zeropkg)
classlist.append(zeropkg.__class__)
classlist.append(zero.__class__)
scanexec[copy(mytreename)] = ScanExecutor(zero,zeropkg)

#########################################################
##########################################################

mytreename = 'crapblaster'
mybranches = ['Bias','Blast Parameters']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {}

cb_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
#connect any like variables that should be simultaneously changed in other scans
cb_tree.data['Bias']['sample bias'] = image_tree.data['Image Parameters']['sample bias']
treelist.append(cb_tree)

class CBPackage(ImagePackage):
	def __init__(self):
		self.TYPE = 'crapblaster'
		ImagePackage.__init__(self)
		self.CB_MAX = cb_tree.data['Blast Parameters'][sv.CB_MAX[2]][0:2]
		self.CB_MIN = cb_tree.data['Blast Parameters'][sv.CB_MIN[2]][0:2]
		self.CB_FREQ = cb_tree.data['Blast Parameters'][sv.CB_FREQ[2]][0:2]
		
	def _complete(self):
		pass

class CBScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._blastCrap()
	
	
cbpkg = CBPackage()
crapblast = CBScan(cbpkg)
classlist.append(cbpkg.__class__)
classlist.append(crapblast.__class__)
scanexec[copy(mytreename)] = ScanExecutor(crapblast,cbpkg)

#########################################################
##########################################################

mytreename = 'ultimate crapblaster pwnage edition'
mybranches = ['Bias','Blast Parameters']
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {}

ucb_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
#connect any like variables that should be simultaneously changed in other scans
ucb_tree.data['Bias']['sample bias'] = image_tree.data['Image Parameters']['sample bias']
ucb_tree.data['Blast Parameters'] = cb_tree.data['Blast Parameters']
treelist.append(ucb_tree)

class UCBPackage(CBPackage):
	def __init__(self):
		self.TYPE = 'ultimate crapblaster pwnage edition'
		CBPackage.__init__(self)
		
	def _complete(self):
		pass

class UCBScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._holdTip()
		self.im._blastCrap()
		self.im._releaseHold()
	
	
ucbpkg = UCBPackage()
ucrapblast = UCBScan(ucbpkg)
classlist.append(ucbpkg.__class__)
classlist.append(ucrapblast.__class__)
scanexec[copy(mytreename)] = ScanExecutor(ucrapblast,ucbpkg)

#########################################################
##########################################################

mytreename = 'rawdata sync' # Set the scan name here
mybranches = ['Storage Options'] # Include the menus you need (defined in scan variables)
mytwignames = menu._fullMenu(mybranches,2)
mytwigvalues = menu._fullMenu(mybranches,0)
mytwigunits = menu._fullMenu(mybranches,1)
mytwigdescr = menu._fullMenu(mybranches,3)
mytwigcell = menu._fullMenu(mybranches,4)
mytwiglimits = {}

dt_tree = MakeTree(mytreename,mybranches,mytwignames,mytwigvalues,mytwigunits,mytwigdescr,mytwigcell,limits=mytwiglimits)
#connect any like variables that should be simultaneously changed in other scans

treelist.append(dt_tree)

class DTPackage(object):
	def __init__(self):
		#ImagePackage.__init__(self)
		self.TYPE = 'rawdata sync'
		#ImagePackage.__init__(self)
		self.RSYNC_FLAGS = dt_tree.data['Storage Options'][sv.RSYNC_FLAGS[2]][0:2]
		self.STORAGE_SERVER = dt_tree.data['Storage Options'][sv.STORAGE_SERVER[2]][0:2]
		self.SSH_USER = dt_tree.data['Storage Options'][sv.SSH_USER[2]][0:2]
		self.REMOTE_PATH = dt_tree.data['Storage Options'][sv.REMOTE_PATH[2]][0:2]
		
	def _complete(self):
		'''
		Chronology-dependent data that gets run at the completion of a scan. May also be used to get
		information about the controller.
		
		'''
		pass

class DTScan(object):
	'''
	Instances of the scan class are sent to the controller to perform
	the actual scan. Other than the standard __init__ function, the controller
	automatically executes 2 other functions (_getMethods and _doScan).
	
	'''
	def __init__(self,package):
		self.package = package

	def _getMethods(self,queues,analog_io,digital_io):
		'''
		Imports hardware reference information into the class for direct use by the ImageOperations
		class in the scan module. Once an instance of the class ImageOperations has been
		made, all the functionality of the controller can be used by the _doScan function.
		
		Keyword Arguments:
		queues -- a list of the queues used for passing data between client and controller
		analog_io -- the list of all required analog devices
		digital_io -- the list of all required digital devices
		
		'''
		from controller.scan import ImageOperations
		self.im = ImageOperations(self.package,queues,analog_io,digital_io)
	
	def _doScan(self):
		'''
		A scan composed from the list of functions supplied by the ImageOperations class.
		On the client side, an instance is made of this class and passed over a socket.
		After getting information about the hardware, this function is executed. Writing new
		scans is relatively easy. Simply find the functions you want to use in the ImageOperations
		class and arrange them as desired.
		
		'''
		self.im._rsyncData()
	
	
dtpkg = DTPackage()
datasync = DTScan(dtpkg)
classlist.append(dtpkg.__class__)
classlist.append(datasync.__class__)
scanexec[copy(mytreename)] = ScanExecutor(datasync,dtpkg)

#########################################################
class PlantTrees(object):
	'''
	Does what the name says! Takes all of the so-called trees and arranges them in
	the wxpython tree widget for convenient display.
	
	'''
	colors = {'0':ws.GRID_NORMAL,'1':ws.GRID_READONLY,'2':ws.GRID_INFO}
	def __init__(self, wxtree):
		self.treewidget = wxtree
		self.treeids = []
		self.branchids = []
		self.twigids = []
		self.treebytreename = {}
		#self.grid = grid
		self._set()
		
	def _set(self):
		'''
		Oh god sometimes it's so hard to explain stuff.
		
		'''
		self.treeroot = self.treewidget.AddRoot('Root')
		for tree in treelist:
			treeid = self.treewidget.AppendItem(self.treeroot,tree.treename)
			self.treebytreename[tree.treename] = tree
			self.treeids.append(treeid)
			branches = self.AddTreeNodes(treeid,tree.branches)
			self.branchids = branches + self.branchids
			for i,branch in enumerate(branches):
				twigs = self.AddTreeNodes(branch, tree.data[tree.branches[i]])
				self.twigids = twigs + self.twigids
		
	
	def _reset(self):
		'''
		Resets the tree display. Deletes everything in the tree and uses the _set
		function to re-create the tree.
		
		'''
		self.treewidget.DeleteAllItems()
		self._set()
	
	def AddTreeNodes(self, parentItem, childlist):
		'''
		Creates the nodes in the tree. Nodes are all of the expandable items.
		
		Keyword Arguments:
		parentItem -- the parent of the new node
		childlist -- the wx id list of the child items to go under the parent
		
		'''
		childids = []
		for child in childlist:
			if type(child) == str:
				childids.append(self.treewidget.AppendItem(parentItem, child))
			else:
				newItem = self.treewidget.AppendItem(parentItem, branch[0])
				self.AddTreeNodes(newItem, branch[0])
		return childids
	
	def setBranch(self, grid, branchid):
		'''
		Displays the data in the branch on the wx grid widget.
		
		Keyword Arguments:
		grid -- the wxgrid widget object
		branchid -- the wx id of the branch object
		
		'''
		self.clearLast(grid) #clear the grid
		treename = self.treewidget.GetItemText(self.treewidget.GetItemParent(branchid))
		tree = self.treebytreename[treename]
		branch = self.treewidget.GetItemText(branchid)
		count = 0
		for i,twig in enumerate(tree.twigs[branch]):
			count += 1
			grid.SetCellValue(i,0,twig)
			grid.SetCellValue(i,1,str(tree.data[branch][twig][0]))
			grid.SetCellValue(i,2,tree.data[branch][twig][1])
			
			##set the defined read-only status for the cell
			grid.SetReadOnly(i,1,int(tree.data[branch][twig][3][0]))
			
			##set the defined colors for each row
			grid.SetCellBackgroundColour(i,0,self.colors[tree.data[branch][twig][3][1]])
			grid.SetCellBackgroundColour(i,1,self.colors[tree.data[branch][twig][3][1]])
			grid.SetCellBackgroundColour(i,2,self.colors[tree.data[branch][twig][3][1]])
		#for i in range(count,10):
			#grid.SetReadOnly(i,1,1)
		
	def setTwig(self,grid,twigid,branchid):
		'''
		Display the value of the individual twig in the grid.
		
		Keyword Arguments:
		grid -- the wxgrid widget object
		twigid -- the wx id of the twig object
		branchid -- the wx id of the branch object
		
		'''
		self.clearLast(grid)
		treename = self.treewidget.GetItemText(self.treewidget.GetItemParent(branchid))
		tree = self.treebytreename[treename]
		branch = self.treewidget.GetItemText(branchid)
		twig = self.treewidget.GetItemText(twigid)
		grid.SetCellValue(0,0,twig)
		grid.SetCellValue(0,1,str(tree.data[branch][twig][0]))
		grid.SetCellValue(0,2,tree.data[branch][twig][1])
		
	def clearLast(self,grid):
		'''
		Clears the grid by setting all values to a blank value
		and changing the color to white.
		
		Keyword Arguments:
		grid -- the wxgrid widget object
		
		'''
		for j in range(3):
			for i in range(10):
				grid.SetCellValue(i,j,'')
				grid.SetCellBackgroundColour(i,j,'#FFFFFF')
				grid.SetReadOnly(i,1,1)
	
	def GetItemText(self, item):
		'''
		Grabs the item text from the tree.
		
		Keyword Arguments:
		item -- the desired item from which to get the text
		
		'''
		if item:
			return self.treewidget.GetItemText(item)
		else:
			return ''

